package did

import (
	"bytes"
	"encoding/base64"
	"encoding/json"
	"fmt"
	"io"
	"mime/multipart"
	"net/http"
	"os"
	"path/filepath"

	"github.com/gin-gonic/gin"
	"github.com/spf13/viper"
)

type DID struct {
	Did string `json:"did"`
}

func (d *DID) String() string {
	return fmt.Sprintf("DID: %s", d.Did)
}

var apiUrls = map[string]string{
	"beatefulImgUrl":     "/process_image",
	"imgVideoToVideoUrl": "/forward/uploadfiles",
}

func NewDID() *DID {
	return &DID{}
}

type DIDBeatefulImgResponse struct {
	RestoredFaces []string `json:"restored_faces"`
	CroppedFaces  []string `json:"cropped_faces"`
	FinalFaces    []string `json:"final_results"`
	// ColorFinalResults []string `json:"color_final_results"`
	ColorFinalResults []string `json:"colorized_results"`
}

// 声明三个数据其一

func (d *DID) BeatefulImg(c *gin.Context, ty string) ([]string, error) {

	if ty != "final" && ty != "cropped" && ty != "restored" && ty != "color" {
		ty = "final"
	}

	// 把c中上传的图片转发给did
	file, handler, err := c.Request.FormFile("file")
	if err != nil {
		return []string{}, err
	}
	defer file.Close()

	body := &bytes.Buffer{}
	writer := multipart.NewWriter(body)
	part, _ := writer.CreateFormFile("file", handler.Filename)
	io.Copy(part, file)
	writer.Close()

	req, err := http.NewRequest("POST", viper.GetString("did.baseUrl")+apiUrls["beatefulImgUrl"], body)
	if err != nil {
		return []string{}, err
	}
	req.Header.Set("Content-Type", writer.FormDataContentType())
	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		return []string{}, err
	}
	defer resp.Body.Close()

	// 读取resp的body中的json内容
	var didResp DIDBeatefulImgResponse // 用于接收did返回的json
	json.NewDecoder(resp.Body).Decode(&didResp)

	var didArr []string
	var resArr []string
	if ty == "final" {
		didArr = didResp.FinalFaces
	}

	if ty == "cropped" {
		didArr = didResp.RestoredFaces
	}

	if ty == "restored" {
		didArr = didResp.FinalFaces
	}

	if ty == "color" {
		didArr = didResp.ColorFinalResults
	}

	// 保存resp里的图片到临时文件夹
	// 检查是否有临时文件夹
	if _, err := os.Stat(viper.GetString("did.tmpPath")); os.IsNotExist(err) {
		os.Mkdir(viper.GetString("did.tmpPath"), os.ModePerm)
	}

	// 遍历didArr
	for i, v := range didArr {
		fileFullName := viper.GetString("did.tmpPath") + fmt.Sprintf("/%d.png", i)
		out, err := os.Create(fileFullName)
		if err != nil {
			return []string{}, err
		}
		defer out.Close()

		ddd, _ := base64.StdEncoding.DecodeString(v)
		_, err = io.Copy(out, bytes.NewReader(ddd))
		if err != nil {
			return []string{}, err
		}

		resArr = append(resArr, fileFullName)
	}

	// fmt.Println(didResp)
	// 保存图片到临时文件夹 didResp.FinalFaces[0] 是did返回的base64图片
	return resArr, nil
}

func (d *DID) BeatefulImg2(c *gin.Context, ty string) (string, error) {

	if ty != "final" && ty != "cropped" && ty != "restored" && ty != "color" {
		ty = "final"
	}

	// 把c中上传的图片转发给did
	file, handler, err := c.Request.FormFile("image")
	if err != nil {
		return "", err
	}
	defer file.Close()

	body := &bytes.Buffer{}
	writer := multipart.NewWriter(body)
	part, _ := writer.CreateFormFile("file", handler.Filename)
	io.Copy(part, file)
	writer.Close()

	req, err := http.NewRequest("POST", viper.GetString("did.baseUrl")+apiUrls["beatefulImgUrl"], body)
	if err != nil {
		return "", err
	}
	req.Header.Set("Content-Type", writer.FormDataContentType())
	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		return "", err
	}
	defer resp.Body.Close()

	// 保存resp里的图片到临时文件夹
	// 检查是否有临时文件夹
	if _, err := os.Stat(viper.GetString("did.tmpPath")); os.IsNotExist(err) {
		os.Mkdir(viper.GetString("did.tmpPath"), os.ModePerm)
	}

	out, err := os.Create(viper.GetString("did.tmpPath") + "/c.png")
	if err != nil {
		return "", err
	}
	defer out.Close()

	// 读取resp的body中的json内容
	var didResp DIDBeatefulImgResponse // 用于接收did返回的json
	json.NewDecoder(resp.Body).Decode(&didResp)
	// fmt.Println(didResp)
	// 保存图片到临时文件夹 didResp.FinalFaces[0] 是did返回的base64图片
	var ddd []byte
	if ty == "final" {
		ddd, _ = base64.StdEncoding.DecodeString(didResp.FinalFaces[0])
	}

	if ty == "cropped" {
		ddd, _ = base64.StdEncoding.DecodeString(didResp.CroppedFaces[0])
	}

	if ty == "restored" {
		ddd, _ = base64.StdEncoding.DecodeString(didResp.RestoredFaces[0])
	}

	if ty == "color" {
		ddd, _ = base64.StdEncoding.DecodeString(didResp.ColorFinalResults[0])
	}

	_, err = io.Copy(out, bytes.NewReader(ddd))
	if err != nil {
		return "", err
	}

	return viper.GetString("did.tmpPath") + "/c.png", nil
}

func (d *DID) ImgVideoToVideo(c *gin.Context, t int) (string, error) {

	body := &bytes.Buffer{}

	// 读取c中的图片
	img, handler, err := c.Request.FormFile("image")
	if err != nil {
		fmt.Println("get c.Request.FormFile image error")
		return "", err
	}
	defer img.Close()

	writer := multipart.NewWriter(body)
	partImg, _ := writer.CreateFormFile("image", handler.Filename)
	io.Copy(partImg, img)

	// 把t对应的视频加载到body中
	filename := fmt.Sprintf("demo%d.mp4", t)
	demoVideo := viper.GetString("did.demoVideoPath") + filename
	demoVideoFile, err := os.Open(demoVideo)
	if err != nil {
		fmt.Println("open demo video file error")
		return "", err
	}
	defer demoVideoFile.Close()

	partFile, _ := writer.CreateFormFile("file", filename)
	io.Copy(partFile, demoVideoFile)

	writer.Close()

	// 打印body
	// fmt.Println(body)

	res, err := http.NewRequest("POST", viper.GetString("did.baseUrl")+apiUrls["imgVideoToVideoUrl"], body)
	if err != nil {
		fmt.Println("http.NewRequest error")
		return "", err
	}

	// 创建一个文件用于保存
	outVideoPath := viper.GetString("did.tmpPath") + "demo1.mp4"
	out, err := os.Create(outVideoPath)
	if err != nil {
		fmt.Println("create outVideoPath error")
		return "", err
	}
	defer out.Close()

	// 打印res
	// fmt.Println(res)
	// 然后将响应流和文件流对接起来 这里会报错超时
	resBody, _ := io.ReadAll(res.Body)
	_, err = io.Copy(out, bytes.NewReader(resBody))
	defer res.Body.Close()
	if err != nil {
		fmt.Println("io.Copy error")
		return "", err
	}

	return outVideoPath, nil
}

func (d *DID) ImgToVideo2(c *gin.Context, t int) (string, error) {
	url := viper.GetString("did.baseUrl") + apiUrls["imgVideoToVideoUrl"]
	method := "POST"

	filename := fmt.Sprintf("demo%d.mp4", t)
	demoVideo := viper.GetString("did.demoVideoPath") + filename
	fmt.Println(demoVideo)
	payload := &bytes.Buffer{}
	writer := multipart.NewWriter(payload)
	file, errFile1 := os.Open(demoVideo)
	if errFile1 != nil {
		fmt.Println(errFile1)
		return "", errFile1

	}
	defer file.Close()
	part1, errFile1 := writer.CreateFormFile("file", filepath.Base(demoVideo))
	if errFile1 != nil {
		fmt.Println(errFile1)
		return "", errFile1

	}
	_, errFile1 = io.Copy(part1, file)
	if errFile1 != nil {
		fmt.Println(errFile1)
		return "", errFile1
	}

	// 读取c中的图片
	img, handler, err := c.Request.FormFile("image")
	if err != nil {
		fmt.Println("get c.Request.FormFile image error")
		return "", err
	}
	defer img.Close()

	partImg, _ := writer.CreateFormFile("image", handler.Filename)
	io.Copy(partImg, img)

	writer.Close()

	client := &http.Client{}
	req, err := http.NewRequest(method, url, payload)

	if err != nil {
		fmt.Println(err)
		return "", err
	}
	req.Header.Set("Content-Type", writer.FormDataContentType())
	res, err := client.Do(req)
	if err != nil {
		fmt.Println(err)
		return "", err
	}
	defer res.Body.Close()

	// 把 res.Body 的内容读写成a.mp4

	out, err := os.Create(viper.GetString("did.tmpPath") + "demo.mp4")
	if err != nil {
		fmt.Println(err)
		return "", err
	}
	defer out.Close()

	_, err = io.Copy(out, res.Body)
	if err != nil {
		fmt.Println(err)
		return "", err
	}
	return viper.GetString("did.tmpPath") + "demo.mp4", nil
}

func (d *DID) LocalImgToVideo(imgPath string, t int) (string, error) {
	url := viper.GetString("did.baseUrl") + apiUrls["imgVideoToVideoUrl"]
	method := "POST"
	filename := fmt.Sprintf("demo%d.mp4", t)
	demoVideo := viper.GetString("did.demoVideoPath") + filename

	payload := &bytes.Buffer{}

	writer := multipart.NewWriter(payload)

	file, errFile1 := os.Open(demoVideo)
	if errFile1 != nil {
		fmt.Println(errFile1)
		return "", errFile1

	}
	defer file.Close()
	part1, errFile1 := writer.CreateFormFile("file", filepath.Base(demoVideo))
	if errFile1 != nil {
		fmt.Println(errFile1)
		return "", errFile1

	}
	_, errFile1 = io.Copy(part1, file)
	if errFile1 != nil {
		fmt.Println(errFile1)
		return "", errFile1
	}

	// 读取c中的图片
	img, err := os.Open(imgPath)
	if err != nil {
		fmt.Println("get local image error")
		return "", err
	}
	defer img.Close()

	partImg, _ := writer.CreateFormFile("image", filepath.Base(imgPath))
	io.Copy(partImg, img)

	writer.Close()

	client := &http.Client{}
	req, err := http.NewRequest(method, url, payload)

	if err != nil {
		fmt.Println(err)
		return "", err
	}
	req.Header.Set("Content-Type", writer.FormDataContentType())
	res, err := client.Do(req)
	if err != nil {
		fmt.Println(err)
		return "", err
	}
	defer res.Body.Close()

	// 把 res.Body 的内容读写成a.mp4

	out, err := os.Create(viper.GetString("did.tmpPath") + "demo.mp4")
	if err != nil {
		fmt.Println(err)
		return "", err
	}
	defer out.Close()

	_, err = io.Copy(out, res.Body)
	if err != nil {
		fmt.Println(err)
		return "", err
	}
	return viper.GetString("did.tmpPath") + "demo.mp4", nil
}
